
#include "SuperBlock.h"

using namespace std;

SuperBlock::SuperBlock()
{
	//TODO:
	//create root with a new inode number, and update the root Inode number.
	_rootInodeNumber = 0;
}

SuperBlock::~SuperBlock()
{

}


/*calculates:	number of blocks
*				number of free blocks (before and after allocation)
 *				number of free iNodes
 *				offset of first Free Block
 *				offset of last free block (for adding)- refers to free space
 *				offset of first Free Inode
 *				offset of lastI node
 *				number of free blocks
 * */
void SuperBlock::calc()
{
	_numOfBlocks = _fileSystemSize/_blockSize; //lower value

	// number of blocks taken by iNodes - array
	int iNodeBlocks = (int)ceil((double)_iNodeArraySize*sizeof(Inode)/_blockSize);


	// num = total - superblock - inodeArraysize(number of blocks for all inodes)
	_freeBlocksNum = _numOfBlocks - (3 + iNodeBlocks); //********************

	_freeInodesNum = _iNodeArraySize - 1; //not counting root

	_firstFreeBlockOffset = 1 * _blockSize; // first address of a free block
	_firstFreeInodeOffset = 2 * _blockSize; // pointers

	//offset of second node in free block list (first of blocks outside superBlock)
	 _freeBlockListOffsetOutsideSB = (3 + iNodeBlocks) * _blockSize;

	// number of nodes in free block list (including superblock)
	//  = number of blocks * int / place in block (without last entry)
	_numOfBlockNodes = (int)ceil((double)_freeBlocksNum * 4 / (_blockSize-4)) + 1;//*************
	int pointersPerBlock = (_blockSize/sizeof(int))-1;
	_entriesPerBlock = _blockSize/sizeof(int);

	// points to next free space in last node of free-block-list
	int lastBlockOffsetTMP = 	_freeBlockListOffsetOutsideSB +	//first entry (outside superblock)
						(_freeBlocksNum-pointersPerBlock) * 4 ;	// number or entries (excluding ones in SuperBlock)

	int numOfPtrBlocks = 	(getBeginningOfBlock(lastBlockOffsetTMP) - _freeBlockListOffsetOutsideSB) / _blockSize; //number of entries used for 'pointers'
	_lastBlockOffset = lastBlockOffsetTMP + numOfPtrBlocks*4;

	_rootInodeOffset = 3 * _blockSize;//first inode, after superblock
//		int firstFreeInodeAddress = rootInodeOffset + sizeof(Inode);


	//offset of second node in free node list (first of blocks outside superBlock)
	_freeInodeListOffsetOutsideSB = (3 + iNodeBlocks + _numOfBlockNodes -1 ) * _blockSize;

	_numOfInodeNodes = ceil((double)_iNodeArraySize * 4 / (_blockSize - 4)) + 1; //one extra

	// points to next free space in last node of free-inode-list
	int lastInodeOffsetTMP =	_freeInodeListOffsetOutsideSB +	//first entry (outside superblock)
								(_iNodeArraySize-pointersPerBlock-1)* 4;		// not counting pointers in SB and root
	numOfPtrBlocks = (getBeginningOfBlock(lastInodeOffsetTMP) - _freeInodeListOffsetOutsideSB) / _blockSize; //number of entries used for 'pointers'
	_lastInodeOffset = lastInodeOffsetTMP + numOfPtrBlocks*4;


	// considering blocks used for free iNode/block lists
	_freeBlocksNum -= ((_numOfBlockNodes-1) + (_numOfInodeNodes-1));

	//  TODO:use later                  = last address in last block, go to beginning,    skip block
	int firstFreeBlock = getBeginningOfBlock(_lastInodeOffset) + _blockSize;
}

int SuperBlock::getEntriesPerBlock()
{
	return _entriesPerBlock;

}
void SuperBlock::setLastInodeOffset(int offset)
{
	_lastInodeOffset = offset;
}

void SuperBlock::setLastBlockOffset(int offset)
{
	_lastBlockOffset = offset;
}



int SuperBlock::getBeginningOfBlock(int add)
{
	return add - (add % _blockSize);

}

//returns if offset in SB points to next block
// should be called before allocating
bool SuperBlock::SBInodeIsEmpty()
{
	//		current   -       starting point  = all block
	return _firstFreeInodeOffset - (2 * _blockSize) == _blockSize - 4;

}

bool SuperBlock::SBBlockIsEmpty()
{
	//		current   -       starting point  = all block
	return _firstFreeBlockOffset - (1 * _blockSize) == _blockSize - 4;
}


// returns number of inode according to its address
int SuperBlock::getInodeNumber(int offset)
{
	if(offset<_rootInodeOffset)
	{
		cout<<"Wrong Offset was given to ""getInodeNumber"""<<endl;
		return -1;
	}
	return (offset -_rootInodeOffset) / sizeof(Inode);
}

int SuperBlock::getNumOfInodeListNodes()
{
	return _numOfInodeNodes;
}

int SuperBlock:: getNumOfBlockListNodes()
{
	return _numOfBlockNodes;
}


int SuperBlock::getFreeBlockListOffsetOutsideSB()
{
	return _freeBlockListOffsetOutsideSB;
}

int SuperBlock::getFreeInodeListOffsetOutsideSB()
{
	return _freeInodeListOffsetOutsideSB;
}

void SuperBlock::setFreeInodeListOffsetOutsideSB(int addr)
{
	_freeInodeListOffsetOutsideSB = addr;
}

void SuperBlock::setFreeBlockListOffsetOutsideSB(int addr)
{
	_freeBlockListOffsetOutsideSB = addr;
}


int SuperBlock::getInodeArrayOffset()
{
	return _rootInodeOffset;
}

int SuperBlock::getFirstFreeBlockOffset()
{
	if( _firstFreeBlockOffset==0)
	{
		cout<<" _firstFreeBlockOffset not set"<<endl;
	}
	return _firstFreeBlockOffset;
}



// returns offset of pointer  to next free inode
int SuperBlock::getFirstFreeInodeOffset()
{
	if(_firstFreeInodeOffset ==0)
	{
		cout<<"_firstFreeInodeOffset not set"<<endl;
	}

	return _firstFreeInodeOffset;
}



// sets pointer(offset) to relative offset
void SuperBlock::addtoFirstFreeInodeOffset(int offset)
{
	_firstFreeInodeOffset += offset;
}

void SuperBlock::addtoFirstFreeBlockOffset(int offset)
{
	_firstFreeBlockOffset += offset;
}


int SuperBlock::getLastInodeOffset()
{
	if( _lastInodeOffset==0)
	{
		cout<<"_lastInodeOffset not set"<<endl;
	}
	return _lastInodeOffset;
}

int SuperBlock::getLastBlockOffset()
{
	return _lastBlockOffset;
}

int SuperBlock::getFileSystemSize()
{
	if(_fileSystemSize ==0)
	{
		cout<<"_fileSystemSize not set"<<endl;
	}
	return _fileSystemSize;
}

void SuperBlock::setFileSystemSize(int fileSystemSize)
{
	this->_fileSystemSize = fileSystemSize;
}

int SuperBlock::getBlockSize()
{
	return _blockSize;
}

void SuperBlock::setBlockSize(int blockSize)
{
	_blockSize = blockSize;
}

int SuperBlock::getRootInodeNumber()
{
	return _rootInodeNumber;
}


int SuperBlock::getFreeBlocksNum()
{
	if(_freeBlocksNum ==0)
	{
		cout<<"_freeBlocksNum not set"<<endl;
	}
	return _freeBlocksNum;
}

void SuperBlock::setFreeBlocksNum(int freeBlocksNum)
{
	this->_freeBlocksNum = freeBlocksNum;
}

int SuperBlock::getINodeArraySize()
{
	if(_iNodeArraySize ==0)
	{
		cout<<"_iNodeArraySize not set"<<endl;
	}
	return _iNodeArraySize;
}

//number of inodes
void SuperBlock::setNodeArraySize(int iNodeArraySize)
{
	this->_iNodeArraySize = iNodeArraySize;
}

int SuperBlock::getFreeInodesNum()
{
	return _freeInodesNum;
}

void SuperBlock::incFreeInodesNum()
{
	_freeInodesNum++;
}

void SuperBlock::decFreeInodesNum()
{
	_freeInodesNum--;
}

void SuperBlock::incFreeBlocksNum()
{
	_freeInodesNum++;
}

void SuperBlock::decFreeBlocksNum()
{
	_freeInodesNum--;
}



void SuperBlock::printSB()
{
	cout<<"file sys size is " << _fileSystemSize <<endl;
	cout<<"block size is " <<_blockSize<<endl;
	cout<<"root inode number is " <<_rootInodeNumber << endl;
	cout<<"the number of free block is " << _freeBlocksNum<< endl;
	cout<<"the i node array size is " << _iNodeArraySize<< endl;
	cout<<"number of free inodes is " <<_freeInodesNum << endl;
}
